# coding: utf-8
# 使用误差反向传播法求解梯度（较之数值微分更为高效），以此来实现神经网络的学习

import sys, os
sys.path.append(os.pardir)

import numpy as np
from dataset.mnist import load_mnist
from two_layer_net import TwoLayerNet
from common.optimizer import *

# 读入数据
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)

# 神经网路
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)

# 优化器
# optimizer = SGD()
# optimizer = Momentum()
# optimizer = AdaGrad()
optimizer = Adam()

iters_num = 10000  # 学习次数，并不是简单的提高学习次数就能提高识别精确度哦
train_size = x_train.shape[0]  # 总数据量
batch_size = 100  # 每次学习数量
learning_rate = 0.1  # 学习速率

train_loos_list = []  # 记录损失函数值
train_acc_list = []  # 记录训练数据识别精确度
test_acc_list = []  # 记录测试数据识别精确度

iter_per_epoch = max(train_size / batch_size, 1)  # 测试周期，类似于你学习了一段时间后，就要单元测试检测你一下，这里每次学100条数据，一共60000条数据，他的周期单位epoch 就设置为训练600次后，测试一次

# 开始训练
for i in range(iters_num):
    batch_mask = np.random.choice(train_size, batch_size)  # 随机抽取固定数量的数据
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]

    # 求解梯度（误差反向传播法）
    grad = network.gradient(x_batch, t_batch)

    # 根据梯度下降法，更新权参数
    # for key in ('W1', 'b1', 'W2', 'b2'):
    #     network.params[key] -= learning_rate * grad[key]
    ## 来试试在不同的优化器下面，会有什么样不同的效果吧，优化器在上面
    optimizer.update(network.params, grad)



    loss = network.loss(x_batch, t_batch)  # 调参后查看一下损失函数值
    train_loos_list.append(loss)

    if i % iter_per_epoch == 0:
        train_acc = network.accuracy(x_train, t_train)  # 哇，算的是全部数据的耶
        test_acc = network.accuracy(x_test, t_test)
        train_acc_list.append(train_acc)
        test_acc_list.append(test_acc)
        # print("训练数据识别精确度：" + str(train_acc) + "| 测试数据识别精确度：" + str(test_acc))
        print(train_acc, test_acc)
